home *** CD-ROM | disk | FTP | other *** search
/ Gold Medal Software 3 / Gold Medal Software - Volume 3 (Gold Medal) (1994).iso / graphics / 3dvect30.arj / POLY.INC < prev    next >
Text File  |  1993-11-18  |  62KB  |  2,089 lines

  1. ; common routines between 3d1.asm,3d2.asm and 3d3.asm
  2.  
  3.             public poly_fill         ; fill polygon
  4.             public clear_fill        ; clear screen
  5.             public initpages         ; initialize video pages selected
  6.             public flip_page         ; flip between video pages
  7.             public fakeline          ; draw line in memory buffer
  8.             public set_clip_absolute ; set clipping parameters - absolute
  9.             public set_clip_offset   ; set clipping parameters - offset
  10.             public updvectors        ; update vector positions/angles
  11.             public fastimultable     ; fast imul table, dw 0-319 * 200
  12.             public clipped_line      ; draw clipped line from dx,cx to ax,bx colour bp
  13.             public sort_list         ; sort vector list
  14.             public drawvect          ; draw vectors from command list
  15.             public look_at_it        ; force camera to look at object
  16.             public calc_angles       ; calculate angles between objects di,si
  17.             public calc_middle       ; calculate angles of ebx,ecx,ebp into x,y
  18.             public get_displacement  ; calculate difference between objects
  19.             public put_object        ; put object si at ebx,ecx,ebp
  20.             public set_angle         ; set object si to angle ebx,ecx,ebp
  21.             public set_shape         ; set shape of object si to ax
  22.             public set_object_on     ; set object si to on
  23.             public set_object_off    ; guess...
  24.             public resetupd          ; reset clearing limits (for clear_fill)
  25.             public move_si           ; move object si to ebx,ecx,ebp in di
  26.             public twist_si          ; rotate object si to ebx,ecx,ebp in di
  27.             public newfollow         ; select new object for camera to follow
  28.             public where_si          ; where will object si be in di frames?
  29.             public set_finall        ; set xsfinal for object (location)
  30.             public set_finala        ; set vxsfinal for object (angles)
  31.             public point_it          ; point object si at object di
  32.             public point_dir         ; point object si in direction it is moving
  33.             public point_to          ; point object si at location ebx,ecx,ebp
  34.             public set_speed         ; calculate velocity based on angles
  35.             public point_time        ; point obj di to bx,cx,bp in di frames
  36.             public nullpalette       ; only a null cross reference palette
  37.             public set_xref_palette  ; set cross reference pal for object si to ebx
  38.  
  39. ; clears a block from active display page
  40. ;
  41. ; this routine works only if borders of xclip land on even nybbles
  42. ; eg minimum x is 32 - works fine.  but if minimum x is 37, this
  43. ; routine will clear all the way to 32 just the same.  for better clearing,
  44. ; call fill_block routine with lxupdate and lyupdate parameters on stack
  45. ;
  46. ; routine was originally written by matt prichard.  routine was then modified
  47. ; to clear using dwords, and clear to integer borders.
  48. ;
  49. ; entry: lxupdate+0  = left x position of area to fill
  50. ;        lxupdate+2  = top y position of area to fill
  51. ;        lyupdate+0  = right x position of area to fill
  52. ;        lyupdate+2  = bottom y position of area to fill
  53.  
  54.            align 16
  55.  
  56. clear_fill:
  57.            cmp use_clear,no
  58.            je tf_exit                  ; don't use clear routine
  59.  
  60.            mov edi, current_page       ; point to active vga page
  61.  
  62. ;          out_8 sc_index, map_mask    ; set up for plane select, should be already set
  63.            out_8 sc_data, all_planes   ; write to all planes
  64.  
  65.            if usefastborders eq no
  66.            if useborders eq yes
  67.            cld                         ; direction flag = forward
  68.  
  69.            mov ax,lxupdate+0
  70.            mov bx,lxupdate+2
  71.            mov cx,lyupdate+0
  72.            mov dx,lyupdate+2
  73.  
  74.            add ax,xcent        ; center on screen
  75.            add bx,xcent
  76.            add cx,ycents1
  77.            add dx,ycentp1
  78.  
  79.            and ax,0fff8h
  80.            and bx,0fff8h
  81.            add bx,7
  82.  
  83.            cmp ax,cliplt       ; clip to inside borders
  84.            jge s tf_noclip1
  85.            mov ax,cliplt
  86. tf_noclip1:
  87.            cmp bx,xmaxxcent
  88.            jl  s tf_noclip2
  89.            mov bx,cliprt
  90. tf_noclip2:
  91.            cmp cx,cliptp
  92.            jge s tf_noclip3
  93.            mov cx,cliptp
  94. tf_noclip3:
  95.            cmp dx,ymaxycent
  96.            jl  s tf_noclip4
  97.            mov dx,ymaxycent
  98. tf_noclip4:
  99.            mov lxupdate+0,ax
  100.            mov lxupdate+2,bx
  101.            mov lyupdate+0,cx
  102.            mov lyupdate+2,dx
  103.  
  104.            cmp ax,bx
  105.            jg  tf_exit             ; nothing to do!
  106.  
  107.            cmp cx,dx
  108.            jg  tf_exit             ; nothing to do!
  109.  
  110.            mov ax,cx
  111.            mov bx,dx
  112.  
  113.            sub bx,ax               ; get y width
  114.            mov lyupdate+2,bx       ; save in ypos2
  115.  
  116.            else                    ; if not using borders update, clear entire
  117.            mov ax,cliptp           ; area!
  118.            mov bx,ymaxycent
  119.            mov cx,cliplt           ; use  this  if   you  want  to  change   the
  120.            mov lxupdate+0,cx       ; clipping paramters  while  the  program  is
  121.            mov cx,cliprt           ; running, and if you want to have useborders
  122.            mov lxupdate+2,cx       ; = no.  the alternative code to this  is the
  123.            mov dx,bx               ; rept code below. it  is  faster  but  takes
  124.            sub dx,ax               ; more memory.
  125.            mov lyupdate+2,dx
  126.  
  127.            endif
  128.  
  129.            movzx esi,ax
  130.            movzx eax,w [esi*2+fastimultable]  ; mul y1 by bytes per line
  131.            add edi,eax             ; di = start of line y1
  132.  
  133.            mov dx,lxupdate         ; dx = x1 (pixel position)
  134.            shr dx,2                ; dx/4 = bytes into line
  135.            movzx edx,dx
  136.            add edi,edx             ; di = addr of upper-left corner
  137.  
  138.            mov cx,lxupdate+2       ; cx = x2 (pixel position)
  139.            sub cx,lxupdate
  140.            shr cx,3                ; cx/4 = bytes into line
  141.            inc cx
  142.  
  143. ; di = addr of upper left block to fill
  144. ; cx = # of bands to fill in (width)
  145.  
  146.            mov dx,xactual/4        ; dx = di increment
  147.            sub dx,cx               ;  = screen_width-# planes filled
  148.            sub dx,cx
  149.  
  150.            movzx ecx,cx
  151.            mov ebx,ecx             ; bx = quick refill for cx
  152.            mov si,lyupdate+2       ; si = # of lines to fill
  153.            mov ax,background       ; get fill color
  154.            push ax                 ; make 32 bit
  155.            shl eax,16
  156.            pop ax
  157.  
  158.            shr ecx,1
  159.            shr ebx,1
  160.            jnc s tf_middle_loop2
  161.  
  162.            align 4
  163.  
  164. tf_middle_loop1:
  165.            stosw
  166.            rep stosd               ; fill in entire line
  167.  
  168.            mov ecx, ebx            ; recharge cx (line width)
  169.            add edi, edx            ; point to start of next line
  170.            loopx si, tf_middle_loop1  ; loop until all lines drawn
  171.  
  172.            ret
  173.  
  174.            align 16
  175.  
  176. tf_middle_loop2:
  177.            rep stosd               ; fill in entire line, doubleword store
  178.  
  179.            mov ecx, ebx            ; recharge cx (line width)
  180.            add edi, edx            ; point to start of next line
  181.            loopx si, tf_middle_loop2  ; loop until all lines drawn
  182. tf_exit:
  183.            ret                     ; exit
  184.  
  185. ; this rept code generates a huge program  that  wipes  the  screen  FAST
  186. ; only use this if you don't want to change the clipping parameters while
  187. ; the program is running.
  188.  
  189.            else                    ; if useborders = no, clear entire area
  190.  
  191.            mov ax,background       ; get fill color
  192.            shl eax,16              ; make 32 bit
  193.            mov ax,background
  194.  
  195.            i=0                     ; this is a huge but fast method
  196.            rept (ymax-ymin)
  197.            j=0
  198.            rept (xmax-xmin)/4/4
  199.  
  200.            mov d [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],eax
  201.  
  202.            j=j+4
  203.            endm
  204.  
  205.            if (xmax-xmin)/4/4 ne (xmax+8-xmin)/4/4
  206.            mov w [j+xactual/4*(ycenter+ymin)+(xcenter+xmin)/4+xactual/4*i+edi],ax
  207.            endif
  208.  
  209.            i=i+1
  210.            endm
  211. tf_exit:
  212.            ret
  213.  
  214.            endif
  215.  
  216. ; fill starting at oney, from firstbyte to lastbyte
  217.  
  218.            align 16
  219. pf_done:
  220.            pop eax
  221. pf_outearly:
  222.            mov oney,1000           ; reset for next polygon call
  223.            ret
  224.  
  225.            align 16
  226. poly_fill:
  227.  
  228. ;          out_8 sc_index, map_mask ; set up for plane select
  229.  
  230.            xor eax,eax
  231.            mov bx,oney             ; ax=y1
  232.            cmp bx,ymins
  233.            jl s pf_missub
  234.  
  235.            cmp bx,ymaxs
  236.            jge pf_outearly
  237.            sub bx,ymins
  238.            mov ax,bx
  239. pf_missub:
  240.            if usesteel eq yes
  241.            cmp steel,0             ; test to use steel texture
  242.            jl s pf_skipsteel
  243.            mov bl,colq             ; yes, save colour offset and 16 block
  244.            mov steelc,bl
  245.            and steelc,0f0h         ; save base offset of 16 colour block
  246.            shl bl,2                ; colour offset is *2 (small) *4 (large)
  247.            add bl,al               ; make steel always constant
  248.            and bl,03fh             ; colour indexer (so sides look different)
  249.            mov steel ,bl
  250. pf_skipsteel:
  251.            endif
  252.  
  253.            mov ebp,eax             ; indexer to line
  254.            shl bp,1
  255.            add ax, cliptp
  256.  
  257.            mov edi, current_page   ; point to active vga page
  258.            mov esi,eax
  259.            mov ax,w [esi*2+fastimultable] ; mul y1 by bytes per line
  260.  
  261.            add edi,eax             ; di = start of line y1
  262.            xor edx,edx
  263.  
  264. pf_more_lines:
  265.            push edi                ; save right hand position
  266.            mov ax, [firstbyte+ebp]
  267.            cmp ax,xmaxs            ; check if fill done
  268.            jge pf_done
  269.  
  270.            xor ebx,ebx
  271.            if usesteel eq yes
  272.            mov bl,steel            ; use steel texture?
  273.            or  bl,bl
  274.            jl s pf_no_steel
  275.            mov dl,pf_updown[ebx]
  276.            add dl,steelc
  277.            mov colq,dl
  278.            inc bl
  279.            and bl,03fh             ; 16 colours, 32 positions for steel texture
  280.            mov steel,bl
  281. pf_no_steel:
  282.            endif
  283.  
  284.            mov bx,[lastbyte+ebp]
  285.            add ax,xcent
  286.            add bx,xcent
  287.  
  288.            mov dx,ax               ; dx = x1 (pixel position)
  289.            shr dx,2                ; dx/4 = bytes into line
  290.            add edi,edx             ; di = addr of upper-left corner
  291.  
  292.            mov ecx,ebx             ; cx = x2 (pixel position)
  293.            shr cx,2                ; cx/4 = bytes into line
  294.  
  295.            cmp dx,cx               ; start and end in same band?
  296.            jg pf_exit              ; skip if fakeline fails connection
  297.            je pf_one_band_only     ; if so, then special processing
  298.  
  299.            mov ah,colq             ; get fill color
  300.            sub cx,dx               ; cx = # bands -1
  301.            mov si,ax               ; si = plane#(x1)
  302.            and esi,plane_bits      ; if left edge is aligned then
  303.            jz s pf_l_plane_flush   ; no special processing..
  304.  
  305. ; draw "left edge" of 1-3 pixels...
  306.  
  307.            out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
  308.  
  309.            mov [edi], ah           ; fill in left edge pixels
  310.  
  311.            inc edi                 ; point to middle (or right) block
  312.            dec cx                  ; reset cx instead of jmp pf_right
  313.  
  314. pf_l_plane_flush:
  315.            inc cx                  ; add in left band to middle block
  316.  
  317. ; di = addr of 1st middle pixel (band) to fill
  318. ; cx = # of bands to fill -1
  319.  
  320. pf_right:
  321.            mov si,bx               ; get xpos2
  322.            and si,plane_bits       ; get plane values
  323.            cmp si,0003             ; plane = 3?
  324.            je s pf_r_edge_flush    ; hey, add to middle
  325.  
  326. ; draw "right edge" of 1-3 pixels...
  327.  
  328.            out_8 sc_data, right_clip_mask[esi]  ; right edge plane mask
  329.  
  330.            mov esi,edi             ; get addr of left edge
  331.            add esi,ecx             ; add width-1 (bands)
  332.            dec esi                 ; to point to top of right edge
  333.  
  334. pf_right_loop:
  335.            mov [esi], ah           ; fill in right edge pixels
  336.  
  337.            dec cx                  ; minus 1 for middle bands
  338.            jz s pf_exit            ; uh.. no middle bands...
  339.  
  340. pf_r_edge_flush:
  341.  
  342. ; di = addr of upper left block to fill
  343. ; cx = # of bands to fill in (width)
  344.  
  345.            out_8 sc_data, all_planes ; write to all planes
  346.  
  347.            mov dx, xactual/4       ; dx = di increment
  348.            sub dx, cx              ;  = screen_width-# planes filled
  349.  
  350.            mov al, ah              ; colour is in high and low for stosw
  351.  
  352. pf_middle_loop:
  353.            shr cx,1                ; use doubleword transfer
  354.            jnc s pf_ord
  355.            stosb                   ; if cx odd, store byte first
  356. pf_ord:
  357.            rep stosw               ; don't use stosd
  358. pf_exit:
  359.            pop edi
  360.            mov [firstbyte+ebp],1000 ; reset table for next polygon
  361.            mov [lastbyte+ebp],-1000
  362.            add bp,2
  363.            add edi,xactual/4
  364.            jmp pf_more_lines
  365.  
  366. pf_one_band_only:
  367.            cmp ax, cliplt
  368.            jne s pf_nexit
  369.            cmp bx,ax
  370.            je s pf_exit
  371. pf_nexit:
  372.            cmp ax, cliprt
  373.            je s pf_exit
  374.            mov si,ax                  ; get left clip mask, save x1
  375.            and esi,plane_bits         ; mask out row #
  376.            mov al,left_clip_mask[esi] ; get left edge mask
  377.            mov si,bx                  ; get right clip mask, save x2
  378.            and si,plane_bits          ; mask out row #
  379.            and al,right_clip_mask[esi] ; get right edge mask byte
  380.  
  381.            out_8 sc_data, al       ; clip for left & right masks
  382.  
  383.            mov ah,colq             ; get fill color
  384.            mov [edi], ah           ; fill in pixels
  385.            jmp s pf_exit           ; outa here, for this line
  386.  
  387. ; small steel texture, make sure to set shl bl,*1* before skip_steel:
  388.  
  389. ;pf_updown  db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  390. ;           db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
  391. ;           db 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
  392. ;           db 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0
  393.  
  394. ; large steel texture, make sure to set shl bl,*2* before skip_steel:
  395.  
  396. pf_updown  db 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9
  397.            db 10,10,11,11,12,12,13,13,14,14,15,15
  398.            db 15,15,14,14,13,13,12,12,11,11,10,10
  399.            db 9,9,8,8,7,7,6,6,5,5,4,4,3,3,2,2,1,1,0,0
  400.  
  401. fastimultable label word
  402.            i=0
  403.            rept yactual
  404.            dw i*(xactual/4)
  405.            i=i+1
  406.            endm
  407.  
  408. resetupd:                         ; make old update equal current update
  409.            if useborders eq yes
  410.  
  411.            mov ax,xupdate[0]      ; and reset current update
  412.            mov lxupdate[0],ax
  413.            mov ax,xupdate[2]
  414.            mov lxupdate[2],ax
  415.            mov ax,yupdate[0]
  416.            mov lyupdate[0],ax
  417.            mov ax,yupdate[2]
  418.            mov lyupdate[2],ax
  419.            mov ax,xmaxs
  420.            mov bx,xmins1
  421.            mov cx,ymaxs
  422.            mov dx,ymins1
  423.            mov xupdate[0],ax
  424.            mov xupdate[2],bx
  425.            mov yupdate[0],cx
  426.            mov yupdate[2],dx
  427.  
  428.            endif
  429.  
  430.            ret
  431.  
  432. ; hey! where is my postcard! see readme.doc file and send me that postcard!
  433.  
  434. initpages:
  435.            pushw 0
  436.            call set_display_page
  437.  
  438.            pushw 0
  439.            call set_active_page
  440.            pushw 0
  441.            call clear_vga_screen
  442.  
  443.            pushw 1
  444.            call set_active_page
  445.            pushw 0
  446.            call clear_vga_screen
  447.  
  448.            ret
  449.  
  450. flip_page:
  451.            if not pages eq 1
  452.  
  453.            mov ax,display_page
  454.            xor al,1
  455.            push ax
  456.            call set_display_page
  457.  
  458.            mov ax,active_page
  459.            xor al,1
  460.            push ax
  461.            call set_active_page
  462.  
  463.            else
  464.  
  465.            call sync_display
  466.  
  467.            display "Note: Page flipping not allowed with only 1 page"
  468.            display "      See equ.inc to select a mode with more than 1 page"
  469.  
  470.            endif
  471.  
  472.            ret
  473.  
  474. ; draw a line in tables firstbyte,lastbyte
  475. ;
  476. ; line is not drawn on screen  but  is  drawn  in  memory  tables.    to  use,
  477. ; tables  must  be  clear,   (default  is    always    clear),    just    draw
  478. ; line around screen, in any order, then  call  poly_fill.  the  polygon  will
  479. ; be drawn and checked in memory, then poly_fill will plop it on  the  current
  480. ; page.  poly_fill routine clears tables during plot so tables are  ready  for
  481. ; more lines and more polygons.
  482.  
  483.            align 16
  484.  
  485. fakeline:
  486.            mov ax,y1
  487.            cmp y2,ax              ; flip order of points if drawing up
  488.            jg s okorder
  489.            mov bx,x1
  490.            xchg bx,x2
  491.            xchg bx,x1
  492.            xchg ax,y2
  493.            mov y1,ax
  494. okorder:
  495.            cmp ax,oney
  496.            jge s nonewoney
  497.            mov oney,ax
  498. nonewoney:
  499.            if useborders eq yes
  500.  
  501.            cmp ax,yupdate+0       ; update borders for clearing routine
  502.            jge s up_no1
  503.            mov yupdate+0,ax
  504. up_no1:
  505.            mov ax,y2
  506.            cmp ax,yupdate+2
  507.            jng s up_no2
  508.            mov yupdate+2,ax
  509. up_no2:
  510.            mov dx,xupdate+0
  511.            mov cx,xupdate+2
  512.            mov ax,x1
  513.            mov bx,x2
  514.  
  515.            cmp ax,dx
  516.            jge s up_no3
  517.            dec ax
  518.            mov xupdate+0,ax
  519.            mov dx,ax
  520.            inc ax
  521. up_no3:
  522.            cmp bx,cx
  523.            jle s up_no4
  524.            inc bx
  525.            mov xupdate+2,bx
  526.            mov cx,bx
  527.            dec bx
  528. up_no4:
  529.            cmp bx,dx
  530.            jge s up_no5
  531.            dec bx
  532.            mov xupdate+0,bx
  533. up_no5:
  534.            cmp ax,cx
  535.            jle s up_no6
  536.            inc ax
  537.            mov xupdate+2,ax
  538. up_no6:
  539.            endif
  540.  
  541.            mov ax,x2              ; ax=x
  542.            sub ax,x1
  543.            mov bx,y2              ; bx=y
  544.            sub bx,y1
  545.            jle sliver
  546.  
  547.            mov rise,bx
  548.            movsx ebx,bx
  549.  
  550.            shl eax,16
  551.            cdq
  552.            idiv ebx
  553.            mov ebp,eax            ; ebp = slope*65536 (allows decimals)
  554.  
  555.            mov ax,ymins
  556.            cmp y1,ax              ; check if above screen
  557.            jge s li_abov1
  558.            sub ax,y1              ; ax = abs(difference of ymin-y1)
  559.            sub rise,ax            ; dec counter
  560.            jle li_out             ; line totally off screen
  561.  
  562.            movsx eax,ax           ; prepare for 32bit mul
  563.            imul ebp
  564.            shr eax,16             ; get top word
  565.            add x1,ax              ; set new x1,y1 pair
  566.            mov ax,ymins
  567.            mov y1,ax
  568. li_abov1:
  569.            movsx edx,x1
  570.            shl edx,16
  571.            mov cx,rise
  572.            mov ax,y1
  573.            movzx ebx,ax           ; bx pointer first/lastbyte table
  574.            sub bx,ymins
  575.            shl bx,1               ; bx now word
  576.  
  577.            add ax,cx              ; will line go off bottom of screen?
  578.            cmp ax,ymaxs
  579.            jl s linep             ; no...
  580.            sub ax,ymaxs           ; yes, truncate cx for early exit
  581.            sub cx,ax
  582.            jle s li_out           ; right off screen
  583. linep:
  584.            mov eax,edx
  585.            movzx ecx,cx
  586.  
  587.            mov di,xmins
  588.            mov si,xmaxs1
  589.  
  590.            align 16
  591. lineloop:
  592.            shr edx,16             ; main line drawing loop!!!
  593.  
  594.            cmp dx,di
  595.            jg s nou
  596.            mov dx,di
  597. nou:
  598.            cmp dx,si
  599.            jl s noq
  600.            mov dx,si
  601. noq:
  602.            cmp dx,firstbyte[ebx]  ; fix first and lastbyte table
  603.            jge s ci1
  604.            mov firstbyte[ebx],dx
  605. ci1:
  606.            cmp dx,lastbyte[ebx]
  607.            jng s ci2
  608.            mov lastbyte[ebx],dx
  609. ci2:
  610.            add eax,ebp
  611.            mov edx,eax
  612.            add bx,2
  613.            loop s lineloop
  614. li_out:
  615.            ret
  616.            align 16
  617. sliver:
  618.            movzx ebx,y1           ; bx pointer first/lastbyte table
  619.  
  620.            cmp bx,ymaxs
  621.            jge li_out
  622.            cmp bx,ymins           ; clip to borders
  623.            jl  li_out
  624.  
  625.            sub bx,ymins
  626.            shl ebx,1              ; ebx now word
  627.  
  628.            mov cx,x1
  629.            cmp cx,xmins
  630.            jge s nouq1
  631.            mov cx,xmins
  632. nouq1:
  633.            cmp cx,xmaxs
  634.            jl s noqq1
  635.            mov cx,xmaxs1
  636. noqq1:
  637.            cmp cx,firstbyte[ebx]  ; fix first and lastbyte table
  638.            jg s ci1q1
  639.            mov firstbyte[ebx],cx
  640. ci1q1:
  641.            cmp cx,lastbyte[ebx]
  642.            jng s ci6q1
  643.            mov lastbyte[ebx],cx
  644. ci6q1:
  645.            mov cx,x2
  646.            cmp cx,xmins
  647.            jge s nouq2
  648.            mov cx,xmins
  649. nouq2:
  650.            cmp cx,xmaxs
  651.            jl s noqq2
  652.            mov cx,xmaxs1
  653. noqq2:
  654.            cmp cx,firstbyte[ebx]  ; fix first and lastbyte table
  655.            jg s ci1q2
  656.            mov firstbyte[ebx],cx
  657. ci1q2:
  658.            cmp cx,lastbyte[ebx]
  659.            jng s ci6q
  660.            mov lastbyte[ebx],cx
  661. ci6q:
  662.            ret
  663.  
  664.            db "  ----  Hey, What are you doing ripping my code?!  ----  "
  665.  
  666. ; set new clipping parameters where center is in middle of points ax,bx cx,dx
  667. ; where points are absolutes! eg (10,10) (50,50) would be a small window in
  668. ; the top corner of the screen.
  669.  
  670. set_clip_absolute:
  671.  
  672.            mov si,cx             ; calc center based on points
  673.            sub si,ax
  674.            shr si,1
  675.            add si,ax
  676.  
  677.            mov di,dx
  678.            sub di,bx
  679.            shr di,1
  680.            add di,bx
  681.  
  682.            sub ax,si             ; now make points offset from center
  683.            sub cx,si
  684.            sub bx,di
  685.            sub dx,di
  686.  
  687. ; set new clipping parameters. does  all  pre-calculation   for  variables  and
  688. ; resets oney, firstbyte and lastbyte table.  si,di is center of screen.  ax,bx
  689. ; and cx,dx are topleft and botright points to clip to.  clipping will  include
  690. ; minimum clip variables but will exclude maximum clip variables.  eg -160,-100
  691. ; +160,+100, with center 160,100 are valid clip parameters.  points are offsets
  692. ; from center, not absolutes! this allows you to have the camera looking to the
  693. ; left or right of where the pilot/plane is moving  without  having  to  change
  694. ; the camera angle. note: this can only change slightly as  distortion  occures
  695. ; with too large an offset.  make sure to assemble the original file  with  the
  696. ; maximum y size you will ever need so tables are set to correct size.
  697.  
  698. set_clip_offset:
  699.            mov bp,dx
  700.            sub bp,bx
  701.            cmp bp,ymax-ymin  ; check input parameters with assembley restraints
  702.            jg you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this
  703.  
  704.            mov xmins,ax
  705.            mov xmaxs,cx
  706.            mov ymins,bx
  707.            mov ymaxs,dx
  708.            mov xcent,si
  709.            mov ycent,di
  710.  
  711.            mov cliptp,di
  712.            add cliptp,bx
  713.  
  714.            mov ycentp1,di
  715.            inc ycentp1
  716.  
  717.            mov ycents1,di
  718.            dec ycents1
  719.  
  720.            mov clipbt,di
  721.            add clipbt,dx
  722.            dec clipbt
  723.  
  724.            mov cliplt,si
  725.            add cliplt,ax
  726.  
  727.            mov cliprt,si
  728.            add cliprt,cx
  729.            dec cliprt
  730.  
  731.            mov xmaxxcent,si
  732.            add xmaxxcent,cx
  733.  
  734.            mov ymaxycent,di
  735.            add ymaxycent,dx
  736.  
  737.            mov xmins1,ax
  738.            dec xmins1
  739.  
  740.            mov xmaxs1,cx
  741.            dec xmaxs1
  742.  
  743.            mov ymins1,bx
  744.            dec ymins1
  745.  
  746.            mov ymaxs1,dx
  747.            dec ymaxs1
  748.  
  749.            movsx eax,ax
  750.            movsx ebx,bx
  751.            movsx ecx,cx
  752.            movsx edx,dx
  753.  
  754.            mov xmit,eax
  755.            mov xmat,ecx
  756.            mov ymit,ebx
  757.            mov ymat,edx
  758.  
  759.            sub xmit,tolerance
  760.            add xmat,tolerance
  761.            sub ymit,tolerance
  762.            add ymat,tolerance
  763. you_must_assemble_original_file_with_larger_clipping_parameters_to_achieve_this:
  764.            ret
  765.  
  766.            align 16
  767.  
  768. ; update vector list based on traces_past
  769. ; i could have used a loop but shl ax,cl works faster
  770. ;
  771. ; what i am really doing is:
  772. ;
  773. ; for i = 1 to traces_past
  774. ;  call updvectors
  775. ; next i
  776. ;
  777. ; but instead i am shifting and adding (if bit present) for a faster method
  778. ; you get the idea right?
  779. ;
  780. ; this way, the slower the machine, the faster we move the objects to
  781. ; maintain a universal speed from 486dx66 machine to 386sx25 machine
  782.  
  783. updvectors:
  784.            mov bx, traces_past
  785.            mov bp,bx
  786.            mov traces_past,0
  787.  
  788.            mov dx,1
  789.            xor cl,cl
  790. up_loop:
  791.            shr bl,1
  792.            jnc not_call
  793.            call updvectors2
  794. not_call:
  795.            shl dx,1                ; dx = 1,2,4,8..
  796.            add cl,1                ; cx = 0,1,2,3,4,5,6...
  797.            or  bl,bl               ; all bits clear?
  798.            jne up_loop
  799.  
  800.            cmp wfollow,no          ; check if camera has reached follow object
  801.            je s nretest            ; nothing to follow
  802.            cmp eyeacount,0
  803.            jne s nretest           ; not reached yet
  804.            mov si,wfollow          ; looking at it, re-call newfollow
  805.            mov di,oldspeed
  806.            cmp di,bp
  807.            ja newfollow            ; re-calculate in case its accelerating
  808.  
  809.            jmp just_look_at_it_now_instead_of_calculating
  810. nretest:
  811.            ret
  812.  
  813.            align 16
  814.  
  815. updvectors2:                      ; update vector list - shifted by cl
  816.                                   ; and dec'ed by dx
  817.            i=0
  818.            rept maxobjects+1      ; generate unrolled update loop
  819.            local nupang, nuploc, nuder, nuuder
  820.  
  821.            cmp acount+i*2,0
  822.            je nupang
  823.            sub acount+i*2,dx
  824.            ja nuder
  825.  
  826.            mov acount+i*2,0       ; counter has expired with decimals!, now
  827.            mov ax,vxsfinal+i*2    ; use final position!
  828.            mov vxs+i*2,ax
  829.            mov ax,vysfinal+i*2
  830.            mov vys+i*2,ax
  831.            mov ax,vzsfinal+i*2
  832.            mov vzs+i*2,ax
  833.            jmp nupang           ; outa here
  834.            align 16
  835. nuuder:
  836.            mov lcount+i*2,0
  837.            mov eax,xsfinal+i*4    ; linear counter has expired with carry!
  838.            mov xs+i*4,eax
  839.            mov eax,ysfinal+i*4
  840.            mov ys+i*4,eax
  841.            mov eax,zsfinal+i*4
  842.            mov zs+i*4,eax
  843.            jmp nuploc
  844.            align 16
  845. nuder:
  846.            mov ax,vxadds+i*2      ; update angles
  847.            shl ax,cl
  848.            add ax,vxs+i*2
  849.            mov vxs+i*2,ax
  850.  
  851.            mov ax,vyadds+i*2
  852.            shl ax,cl
  853.            add ax,vys+i*2
  854.            mov vys+i*2,ax
  855.  
  856.            mov ax,vzadds+i*2
  857.            shl ax,cl
  858.            add ax,vzs+i*2
  859.            mov vzs+i*2,ax
  860. nupang:
  861.            cmp lcount+i*2,0
  862.            je nuploc
  863.            sub lcount+i*2,dx
  864.            jna nuuder              ; go backward to avoid instruction buffer flush
  865.            mov eax,xadds+i*4       ; update position
  866.            shl eax,cl
  867.            add eax,xs+i*4
  868.            mov xs+i*4,eax
  869.  
  870.            mov eax,yadds+i*4
  871.            shl eax,cl
  872.            add eax,ys+i*4
  873.            mov ys+i*4,eax
  874.  
  875.            mov eax,zadds+i*4
  876.            shl eax,cl
  877.            add eax,zs+i*4
  878.            mov zs+i*4,eax
  879. nuploc:
  880.            i=i+1
  881.            endm
  882.  
  883.            ret
  884.  
  885.            align 16
  886.  
  887. put_object:
  888.            movzx esi,si
  889.            mov xs[esi*4],ebx
  890.            mov ys[esi*4],ecx
  891.            mov zs[esi*4],ebp
  892.            ret
  893.  
  894.            align 16
  895.  
  896. set_angle:
  897.            movzx esi,si
  898.            mov vxs[esi*2],bx
  899.            mov vys[esi*2],cx
  900.            mov vzs[esi*2],bp
  901.            ret
  902.  
  903.            align 16
  904. set_shape:
  905.            movzx esi,si
  906.            mov whatshape[esi*2],ax
  907.            ret
  908.  
  909.            align 16
  910.  
  911. set_object_on:
  912.            movzx esi,si
  913.            mov onoff[esi],1
  914.            ret
  915.  
  916.            align 16
  917.  
  918. set_object_off:
  919.            movzx esi,si
  920.            mov onoff[esi],0
  921.            ret
  922.  
  923. ; move object si from wherever it is now to ebx,ecx,ebp in di frames
  924. ; move is 32 bit, make sure high words of registers are set!
  925. ; time to get there is 16 bit. (if you need more, think! 65535 frames at
  926. ; 1/30 frames a sec is 36 minutes!)
  927.  
  928.            align 16
  929.  
  930. move_si:
  931.            movzx esi,si
  932.            shl si,2               ; si = dword
  933.  
  934.            mov xsfinal[esi],ebx
  935.            mov ysfinal[esi],ecx
  936.            mov zsfinal[esi],ebp
  937.  
  938.            sub ebx,xs[esi]
  939.            sub ecx,ys[esi]
  940.            sub ebp,zs[esi]
  941.  
  942.            movzx edi,di
  943.  
  944.            mov eax,ebx            ; 32 bit moves
  945.  
  946.            cdq
  947.            idiv edi
  948.            mov xadds[esi],eax
  949.  
  950.            mov eax,ecx
  951.            cdq
  952.            idiv edi
  953.            mov yadds[esi],eax
  954.  
  955.            mov eax,ebp
  956.            cdq
  957.            idiv edi
  958.            mov zadds[esi],eax
  959.  
  960.            shr si,1               ; si = word
  961.  
  962.            mov lcount[esi],di
  963.            shr si,1               ; restore original si
  964.  
  965.            ret
  966.  
  967.            align 16
  968.  
  969. ; rotate object si from wherever it is now to ebx,ecx,ebp in  di  frames
  970. ; rotate is  32 bit, make   sure   high  words  of  registers  are  set!
  971. ; time to get there is 16 bit.  note: although resulting angle  will  be
  972. ; 16 bit, input angle is 32 bit!.  this allows you to rotate many  times
  973. ; before coming to rest at a specified angle  and  also  allows  you  to
  974. ; specify the direction of rotation.    di  specifies  time  to  arrive.
  975. ; final location is absolute, not relative to current angle.
  976.  
  977. ; eg 00000100 is "rotate forwards until 100 degrees"
  978. ;    00078000 is "rotate 7 full rotations and come to rest at 32768 degrees"
  979. ;    fffd9000 is "rotate backwards 2 rotations and come to rest at 9000h degrees"
  980. ;    fffffff0 is "rotate backwards until 65520 degrees (-16)"
  981.  
  982. ; therefore, to reverse the direction of rotation (but maintain  the  final
  983. ; position) xor ebx,0ffff0000h  (or ecx or ebp).  ax is final position, but
  984. ; top word of eax determines direction and number of turn to get there.
  985.  
  986. twist_si:
  987.            movzx esi,si
  988.            shl si,1               ; si = word
  989.  
  990.            mov vxsfinal[esi],bx   ; set final position when acount becomes 0
  991.            mov vysfinal[esi],cx
  992.            mov vzsfinal[esi],bp
  993.  
  994.            movzx eax,vxs[esi]
  995.            sub ebx,eax
  996.            movzx eax,vys[esi]
  997.            sub ecx,eax
  998.            movzx eax,vzs[esi]
  999.            sub ebp,eax
  1000.  
  1001.            movzx edi,di
  1002.  
  1003.            mov eax,ebx            ; 32 bit rotate
  1004.            cdq
  1005.            idiv edi
  1006.            mov vxadds[esi],ax
  1007.  
  1008.            mov eax,ecx
  1009.            cdq
  1010.            idiv edi
  1011.            mov vyadds[esi],ax
  1012.  
  1013.            mov eax,ebp
  1014.            cdq
  1015.            idiv edi
  1016.            mov vzadds[esi],ax
  1017.  
  1018.            mov acount[esi],di
  1019.            shr si,1               ; restore original si
  1020.  
  1021.            ret
  1022.  
  1023.            align 16
  1024.  
  1025. look_at_it:                       ; force camera to look at object wherelook
  1026.            mov si,wherelook
  1027.            cmp si,no
  1028.            je s noat              ; get out, no object to look at (-1=flag)
  1029.  
  1030.            mov edi,cameraobject
  1031.            movzx esi,si
  1032.            call calc_angles       ; calculate difference between camera and obj
  1033.            mov eyeay,bx           ; this is where the camera should look...
  1034.            mov eyeax,ax
  1035. noat:
  1036.            ret
  1037.  
  1038. ; calculate angles between objects esi and edi.  angles are from point of view
  1039. ; of di.
  1040.  
  1041.            align 16
  1042.  
  1043. calc_angles:
  1044.            call get_displacement
  1045.  
  1046. calc_middle:
  1047.            push ecx ebx ebp
  1048.  
  1049.            mov ecx,ebx            ; first get z,x plane, (y angle)
  1050.            mov eax,ebp
  1051.  
  1052.            or  eax,eax
  1053.            je lk_right_above      ; check arctan(cx/0)
  1054.  
  1055.            call arctan
  1056. lk_resume:
  1057.            mov dsq,ax             ; save y angle
  1058.            call cosign            ; set up 32bit sin/cos multipliers
  1059.            mov vycos,eax
  1060.            mov ax,dsq
  1061.            call sign
  1062.  
  1063.            pop ebp ebx            ; now compute sqr(z^2+x^2) through y rotation
  1064.  
  1065.            imul ebx               ; use angle from calculation above
  1066.            shrd eax,edx,14
  1067.            mov edi,eax
  1068.            mov eax,vycos
  1069.            imul ebp
  1070.            shrd eax,edx,14
  1071.            add eax,edi            ; di = new z = run
  1072.  
  1073.            pop ecx                ; cx = rise
  1074.            or  eax,eax
  1075.            je s noaq
  1076.  
  1077.            call arctan            ; get ax=arctan(y/sqr(z^2+x^2))
  1078.  
  1079.            mov bx,dsq             ; bx = y angle , ax = x angle
  1080. noaq:
  1081.            ret
  1082.  
  1083.            align 16
  1084.  
  1085. lk_right_above:
  1086.            mov ax,vys[esi]        ; camera directly above object, use old y
  1087.            jmp lk_resume
  1088.  
  1089.            align 16
  1090.  
  1091. get_displacement:
  1092.            movzx esi,si           ; in case user is lazy
  1093.            movzx edi,di
  1094.  
  1095.            mov ebx,xs[esi*4]      ; get displacement of esi to edi
  1096.            sub ebx,xs[edi*4]
  1097.            mov ecx,ys[esi*4]
  1098.            sub ecx,ys[edi*4]
  1099.            mov ebp,zs[esi*4]
  1100.            sub ebp,zs[edi*4]
  1101.            ret
  1102.  
  1103.            align 16
  1104.  
  1105. ; new follow, si = object for new follow, di = time to get there.
  1106.  
  1107. newfollow:
  1108.            mov wfollow,si         ; save in case object is accelerating
  1109.            mov oldspeed,di
  1110.            mov wherelook,no       ; disable look_at_si routine
  1111.  
  1112.            call where_si          ; figure out where object si will end up
  1113.  
  1114.            mov di,oldspeed        ; figure out where camera will end up
  1115.            mov ax,eyelcount
  1116.            cmp ax,di              ; if di>lcount, shorten to lcount
  1117.            ja s tx
  1118.            mov di,ax
  1119. tx:
  1120.            movzx edi,di
  1121.  
  1122.            mov eax,eyexadds
  1123.            imul edi               ; figure out where camera will be di*frames
  1124.            add eax,eyex
  1125.            sub ebx,eax            ; get displacement to eye
  1126.  
  1127.            mov eax,eyeyadds
  1128.            imul edi
  1129.            add eax,eyey
  1130.            sub ecx,eax
  1131.  
  1132.            mov eax,eyezadds
  1133.            imul edi
  1134.            add eax,eyez
  1135.            sub ebp,eax
  1136.  
  1137.            call calc_middle       ; jump in middle of angle computation
  1138.  
  1139.            mov eyefinalax,ax
  1140.            mov eyefinalay,bx
  1141.  
  1142.            mov di,bx
  1143.  
  1144.            sub ax,eyeax           ; get difference from where we are now
  1145.            sub di,eyeay
  1146.  
  1147.            add ax,followtol       ; check if already looking at it
  1148.            cmp ax,followtol*2
  1149.            ja s calcit
  1150.  
  1151.            add di,followtol
  1152.            cmp di,followtol*2
  1153.            jb just_look_at_it_now_instead_of_calculating
  1154.            sub di,followtol
  1155. calcit:
  1156.            sub ax,followtol
  1157.  
  1158.            mov si,oldspeed        ; ax=x angle, di=y angle, si=# frames
  1159.            cwd
  1160.            push dx                ; save sign extend
  1161.            idiv si                ; x/time
  1162.            pop dx
  1163.            or  ax,ax
  1164.            jne s n0
  1165.            shl dx,1
  1166.            mov ax,dx
  1167.            inc ax                 ; ax = 1 or ax = -1
  1168. n0:
  1169.            mov eyevxadds,ax
  1170.  
  1171.            mov ax,di
  1172.            cwd
  1173.            push dx
  1174.            idiv si                ; y/time
  1175.            pop dx
  1176.            or  ax,ax              ; check if zero slope, must have some...
  1177.            jne s n1
  1178.            shl dx,1               ; dx = fffe (-2) or 0
  1179.            mov ax,dx
  1180.            inc ax                 ; ax = 1 or ax = -1
  1181. n1:
  1182.            mov eyevyadds,ax
  1183.  
  1184.            mov eyeacount,si
  1185.            shr oldspeed,1         ; if need to try again, time/2
  1186.  
  1187.            mov ax,eyevzadds       ; now adjust any z rotation into finalz
  1188.            imul si
  1189.            add ax,eyeaz
  1190.            mov eyefinalaz,ax
  1191.  
  1192.            ret
  1193.  
  1194.            align 16
  1195.  
  1196. just_look_at_it_now_instead_of_calculating:
  1197.            mov ax,wfollow
  1198.            mov wherelook,ax       ; already looking at object, now follow it
  1199.            mov wfollow,no
  1200.            ret
  1201.  
  1202.            align 16
  1203.  
  1204. ; figure out where object si will be in di frames.
  1205.  
  1206. where_si:
  1207.            movzx esi,si
  1208.  
  1209.            mov ax,lcount[esi*2]
  1210.            or  ax,ax
  1211.            jne s nx
  1212.  
  1213.            mov ebx,xs[esi*4]        ; if object has no velocity, xs is position
  1214.            mov ecx,ys[esi*4]
  1215.            mov ebp,zs[esi*4]
  1216.            ret
  1217. nx:
  1218.            cmp ax,di              ; if di>lcount, shorten to lcount
  1219.            ja s nxq
  1220.            mov di,ax
  1221. nxq:
  1222.            movzx edi,di
  1223.  
  1224.            mov eax,xadds[esi*4]   ; figure out where object will be di*frames
  1225.            imul edi
  1226.            add eax,xs[esi*4]
  1227.            mov ebx,eax
  1228.  
  1229.            mov eax,yadds[esi*4]
  1230.            imul edi
  1231.            add eax,ys[esi*4]
  1232.            mov ecx,eax
  1233.  
  1234.            mov eax,zadds[esi*4]
  1235.            imul edi
  1236.            add eax,zs[esi*4]
  1237.            mov ebp,eax
  1238.  
  1239.            ret
  1240.  
  1241.            align 16
  1242.  
  1243. ; draw vectors from sides list.
  1244. ; number of "sides" is "showing"
  1245.  
  1246. dv_none2:
  1247.            ret
  1248. drawvect:
  1249.            cmp showing,0          ; no sides visible?
  1250.            je s dv_none2
  1251.  
  1252.            mov whichside,0        ; start at side 0
  1253.            movzx ebp,order[0]     ; indexer to sides
  1254. dv_loop2:
  1255.            test textures[ebp],line+himap+point ; test if line, point, scalable bitmap or bitmapped texture
  1256.            jnz dv_testit          ; yes, do faster line routine
  1257.  
  1258.            shl bp,mult
  1259.            mov dx,sides[ebp]      ; first point is end flag
  1260. dv_loop1:
  1261.            movzx esi,sides[ebp]   ; get point, shl 1 not needed, pre-shl'ed
  1262.            mov ax,[xp+esi]
  1263.            mov bx,[yp+esi]
  1264.            mov x1,ax
  1265.            mov y1,bx
  1266.  
  1267.            mov si,[sides+ebp+2]   ; get next point
  1268.  
  1269.            cmp si,dx              ; test if last = first, therefore done
  1270.            pushf
  1271.  
  1272.            mov ax,[xp+esi]
  1273.            mov bx,[yp+esi]
  1274.  
  1275.            mov x2,ax
  1276.            mov y2,bx
  1277.  
  1278.            push ebp dx
  1279.            call fakeline          ; draw next line
  1280.            pop dx ebp
  1281.  
  1282.            add bp,2               ; bump to next pointer now
  1283.            popf                   ; was this point equal to the first point?
  1284.            jne s dv_loop1         ; no, draw more lines
  1285.  
  1286.            movzx esi,whichside    ; set colour for this side
  1287.            mov si,order[esi]
  1288.            mov ebx,palxref        ; get offset of palette cross reference table for this object
  1289.            mov al,b surfcolors[esi]
  1290.            xlat
  1291.            mov colq,al
  1292.  
  1293.            mov bx,textures[esi]   ; use register which we can access low byte
  1294.            and bl,wavey           ; strip steel command bit
  1295.            sub bl,wavey
  1296.            mov steel,bl
  1297.  
  1298.            call poly_fill
  1299.  
  1300. dv_return:
  1301.            add whichside,2        ; bump bp to next block of points
  1302.            movzx ebp,whichside
  1303.            mov bp,order[ebp]      ; get sort order
  1304.            dec showing            ; count for all sides
  1305.            jne dv_loop2
  1306. dv_none:
  1307.            ret
  1308.  
  1309.            align 16
  1310. dv_testit:
  1311.            mov ax,textures[ebp]   ; perform command, return to dv_return
  1312.            test al,line
  1313.            jnz dv_doline
  1314.            test al,point
  1315.            jnz dv_dopoint
  1316.  
  1317. ; draw bitmap at location x,y,z if userotate = 32 or command = 32
  1318.  
  1319.            shl bp,mult
  1320.            push ax ebp
  1321.  
  1322.            movzx ebx,[sides+4+ebp]
  1323.            movzx ecx,[sides+6+ebp]
  1324.  
  1325.            movzx esi,[sides+2+ebp]
  1326.            shl si,2               ; si = dword
  1327.            add ebx,bitx[esi]
  1328.            add ecx,bity[esi]      ; ebx,ecx = top corner of bitmap in 3d
  1329.  
  1330.            mov eax,bitbase[esi]
  1331.            mov bitmap,eax
  1332.  
  1333.            mov si,[sides+0+ebp]
  1334.            mov bp,[zp+esi]
  1335.  
  1336.            call make3d            ; ebx,ecx = difference from center
  1337.  
  1338.            pop ebp
  1339.  
  1340.            movzx esi,[sides+0+ebp] ; get point
  1341.            mov ax,[xp+esi]
  1342.            mov bp,[yp+esi]
  1343.  
  1344.            sub ax,bx              ; bx = x width/2  ax, bp = top corner
  1345.            sub bp,cx              ; cx = y height/2
  1346.  
  1347.            if useborders eq yes
  1348.  
  1349.            cmp bp,yupdate+0
  1350.            jge s up_nq12
  1351.            mov yupdate+0,bp
  1352. up_nq12:
  1353.            cmp ax,xupdate+0
  1354.            jge s up_nq32
  1355.            mov xupdate+0,ax
  1356. up_nq32:
  1357.            mov di,ax
  1358.            mov dx,bp
  1359.  
  1360.            endif
  1361.  
  1362.            add ax,xcent
  1363.            add bp,ycent
  1364.            mov destx,ax
  1365.            mov desty,bp
  1366.  
  1367.            shl bx,1
  1368.            shl cx,1
  1369.  
  1370.            mov destwidth,bx
  1371.            mov destheight,cx
  1372.  
  1373.            if useborders eq yes
  1374.            add di,bx
  1375.            add dx,cx
  1376.  
  1377.            cmp dx,yupdate+2
  1378.            jng s up_nq42
  1379.            mov yupdate+2,dx
  1380. up_nq42:
  1381.            cmp di,xupdate+2
  1382.            jng s up_nq22
  1383.            mov xupdate+2,di
  1384. up_nq22:
  1385.            endif
  1386.  
  1387.            pop ax
  1388.            test al,lomap-himap   ; test to use 1/4 scale bitmap or full scale
  1389.            jz s noq19
  1390.  
  1391.            call xscale4
  1392.            jmp dv_return
  1393.  
  1394.            align 16
  1395. noq19:
  1396.            call xscale2
  1397. noq7:
  1398.            jmp dv_return
  1399.  
  1400.            align 16
  1401.  
  1402. dv_dopoint:
  1403.            mov dx,surfcolors[ebp]  ; get colour of point
  1404.  
  1405.            shl bp,mult
  1406.            movzx esi,[sides+ebp]   ; get point x,y
  1407.            mov bx,[xp+esi]
  1408.            mov cx,[yp+esi]
  1409.  
  1410.            cmp bx,xmins            ; check if on screen
  1411.            jl s noq7
  1412.            cmp bx,xmaxs
  1413.            jge s noq7
  1414.            cmp cx,ymins
  1415.            jl s noq7
  1416.            cmp cx,ymaxs            ; ymaxs1 if larger pixel
  1417.            jge s noq7
  1418.  
  1419.            mov edi, current_page   ; point to active vga page
  1420.  
  1421.            if useborders eq yes
  1422.  
  1423.            cmp cx,yupdate+0
  1424.            jge s up_no16
  1425.            mov yupdate+0,cx
  1426. up_no16:
  1427.            cmp bx,xupdate+0
  1428.            jge s up_no36
  1429.            mov xupdate+0,bx
  1430. up_no36:
  1431.            cmp cx,yupdate+2
  1432.            jng s up_no46
  1433.            mov yupdate+2,cx
  1434. up_no46:
  1435.            cmp bx,xupdate+2
  1436.            jng s up_no26
  1437.            mov xupdate+2,bx
  1438. up_no26:
  1439.            endif
  1440.  
  1441.            add bx,xcent
  1442.            add cx,ycent
  1443.  
  1444.            mov bp,dx               ; save colour
  1445.  
  1446.            mov si,cx
  1447.            mov ax,[esi*2+fastimultable] ; get offset to start of line
  1448.  
  1449.            mov cx, bx              ; copy to extract plane # from
  1450.            shr bx, 2               ; x offset (bytes) = xpos/4
  1451.            add bx, ax              ; offset = width*ypos + xpos/4
  1452.  
  1453.            mov ax, map_mask_plane1 ; map mask & plane select register
  1454.            and cl, plane_bits      ; get plane bits
  1455.            shl ah, cl              ; get plane select value
  1456.            out_16 sc_index, ax     ; select plane
  1457.  
  1458.            movzx ebx,bx
  1459.            mov ax,bp               ; re-get colour
  1460.            mov [edi+ebx],al        ; draw pixel, low is top, high is bottom
  1461. ;          add edi,xactual/4
  1462. ;          mov [edi+ebx],ah        ; draw larger bullet/pixel (high byte)
  1463.  
  1464. ; if drawing larger pixel, change above code to this!
  1465. ;          cmp cx,ymaxs1
  1466. ;          jge s noa7
  1467.  
  1468.            jmp dv_return
  1469.  
  1470.            align 16
  1471.  
  1472. ; handle line command from drawvect, uses clipped_line routine
  1473.  
  1474. dv_doline:
  1475.            mov edi,ebp            ; save...
  1476.  
  1477.            mov ebx,palxref        ; get offset of palette cross reference table for this object
  1478.            movzx ecx,b surfcolors[ebp]
  1479.            movzx bp,b [ecx+ebx]
  1480.  
  1481.            shl di,mult
  1482.            movzx esi,[sides+edi]  ; get first point
  1483.            mov dx,[xp+esi]
  1484.            mov cx,[yp+esi]
  1485.  
  1486.            mov si,[sides+edi+2]   ; second point indexer
  1487.  
  1488.            mov ax,[xp+esi]        ; now load up second point
  1489.            mov bx,[yp+esi]
  1490.  
  1491.            call clipped_line
  1492.            jmp dv_return          ; return to drawvect
  1493.  
  1494. ; draw  clipped   line  in  cartesian  format  (0,0   is   screen   center)
  1495. ; similar routine to fakeline but faster,  more accurate and draws directly
  1496. ; to screen (current_page).  updates clearing borders (if used)
  1497. ;
  1498. ; draws line from (dx,cx) to (ax,bx) using colour bp
  1499. ;
  1500. clipped_line:
  1501.            cmp bx,cx              ; flip order of points if drawing up
  1502.            jg s r_okorder
  1503.            xchg bx,cx
  1504.            xchg ax,dx
  1505. r_okorder:
  1506.            mov x1,dx
  1507.            mov y1,cx
  1508.            mov x2,ax
  1509.            mov y2,bx
  1510.  
  1511.            if useborders eq yes
  1512.  
  1513.            cmp cx,yupdate+0       ; update borders for clearing routine
  1514.            jg s r_up_no1
  1515.            mov yupdate+0,cx
  1516. r_up_no1:
  1517.            cmp bx,yupdate+2
  1518.            jng s r_up_no2
  1519.            mov yupdate+2,bx
  1520. r_up_no2:
  1521.            mov bx,ax
  1522.            mov ax,dx
  1523.            mov dx,xupdate+0
  1524.            mov cx,xupdate+2
  1525.  
  1526.            cmp ax,dx
  1527.            jge s r_up_no3
  1528.            dec ax
  1529.            mov xupdate+0,ax
  1530.            mov dx,ax
  1531.            inc ax
  1532. r_up_no3:
  1533.            cmp bx,cx
  1534.            jle s r_up_no4
  1535.            inc bx
  1536.            mov xupdate+2,bx
  1537.            mov cx,bx
  1538.            dec bx
  1539. r_up_no4:
  1540.            cmp bx,dx
  1541.            jge s r_up_no5
  1542.            dec bx
  1543.            mov xupdate+0,bx
  1544. r_up_no5:
  1545.            cmp ax,cx
  1546.            jle s r_up_no6
  1547.            inc ax
  1548.            mov xupdate+2,ax
  1549. r_up_no6:
  1550.            mov ax,x2              ; ax=x
  1551.            sub ax,x1
  1552.            mov bx,y2              ; bx=y
  1553.            sub bx,y1
  1554.  
  1555.            elseif not useborders eq yes
  1556.  
  1557.            sub ax,dx
  1558.            sub bx,cx
  1559.  
  1560.            endif
  1561.  
  1562.            mov dx,bp
  1563.            mov colq,dl
  1564.  
  1565.            mov dx,ymaxs
  1566.            cmp y1,dx
  1567.            jge cl_return
  1568.  
  1569.            mov rise,bx
  1570.            movsx ebx,bx
  1571.            or  ebx,ebx
  1572.            jne s r_nsliver
  1573.  
  1574.            mov bx, y1
  1575.            cmp bx, ymins          ; draw sliver, avoid divide by zero
  1576.            jl cl_return
  1577.            cmp bx, dx             ; dx = ymax
  1578.            jge cl_return
  1579.  
  1580.            add bx,ycent
  1581.            movzx esi,bx
  1582.            movzx eax,[esi*2+fastimultable] ; get offset to start of line
  1583.            mov edi, current_page
  1584.            add edi, eax           ; edi = starting y location
  1585.  
  1586.            mov rise,1
  1587.  
  1588.            mov dx, x1             ; from here...
  1589.            mov si, x2             ;            ..to here
  1590.  
  1591.            cmp si,xmins
  1592.            jge s u_nou3
  1593.            mov si,xmins
  1594. u_nou3:
  1595.            cmp si,xmaxs
  1596.            jl s u_noq3
  1597.            mov si,xmaxs1
  1598. u_noq3:
  1599.            jmp r_splint           ; re-enter draw later in code
  1600.  
  1601.            align 16
  1602. r_nsliver:
  1603.            shl eax,16
  1604.            cdq
  1605.            idiv ebx
  1606.            mov ebp,eax            ; ebp = slope*65536 (allows decimals)
  1607.  
  1608.            mov ax,ymins
  1609.            cmp y1,ax              ; check if above screen
  1610.            jge s r_li_abov1
  1611.            sub ax,y1              ; ax = abs(difference of ymin-y1)
  1612.            sub rise,ax            ; dec counter
  1613.            jle cl_return          ; line totally off screen
  1614.  
  1615.            movsx eax,ax           ; prepare for 32bit mul
  1616.            imul ebp
  1617.            shr eax,16             ; get top word
  1618.            add x1,ax              ; set new x1,y1 pair
  1619.            mov ax,ymins
  1620.            mov y1,ax
  1621.  
  1622. r_li_abov1:
  1623.            mov bx,y1              ; bx distance from top of screen
  1624.            add bx,ycent
  1625.            movzx esi,bx           ; calculate screen address
  1626.            movzx eax,[esi*2+fastimultable] ; get offset to start of line
  1627.            mov edi, current_page
  1628.            add edi,eax            ; edi = starting y location
  1629.  
  1630.            movsx edx,x1
  1631.            shl edx,16
  1632.            mov cx,rise
  1633.            mov ax,y1
  1634.            add ax,cx              ; will line go off bottom of screen?
  1635.            cmp ax,ymaxs
  1636.            jl s r_linep           ; no...
  1637.            sub ax,ymaxs           ; yes, truncate cx for early exit
  1638.            sub rise,ax
  1639.            jle cl_return
  1640. r_linep:
  1641.            mov eax,edx
  1642.            movzx ecx,cx
  1643.  
  1644.            mov esi,edx
  1645.            shr esi,16
  1646.  
  1647.            cmp si,xmins
  1648.            jge s r_nou
  1649.            mov si,xmins
  1650. r_nou:
  1651.            cmp si,xmaxs
  1652.            jl s r_noq
  1653.            mov si,xmaxs1
  1654.  
  1655.            align 16
  1656. r_noq:
  1657.  
  1658. r_lineloop:
  1659.            add eax,ebp             ; main line drawing loop!!! (for lines)
  1660.            mov edx,eax
  1661.            shr edx,16
  1662. r_splint:
  1663.            cmp dx,xmins
  1664.            jge s u_nou
  1665.            mov dx,xmins
  1666.            cmp dx,si
  1667.            je r_mis
  1668. u_nou:
  1669.            cmp dx,xmaxs
  1670.            jl s u_noq
  1671.            mov dx,xmaxs1
  1672.            cmp dx,si
  1673.            je r_mis
  1674. u_noq:
  1675.            push dx edi ebp eax     ; save for next line
  1676.            cmp dx,si
  1677.            jle s r_no_switch
  1678.            xchg dx,si
  1679. r_no_switch:
  1680.  
  1681.            add dx,xcent
  1682.            add si,xcent
  1683.  
  1684.            mov ax,dx
  1685.            mov bx,si
  1686.            mov x2,si
  1687.  
  1688.            shr dx,2                ; dx/4 = bytes into line
  1689.            movzx edx,dx
  1690.            add edi,edx             ; di = addr of upper-left corner
  1691.  
  1692.            movzx ecx,bx            ; cx = x2 (pixel position)
  1693.            shr cx,2                ; cx/4 = bytes into line
  1694.  
  1695.            cmp dx,cx               ; start and end in same band?
  1696.            je  rf_one_band_only    ; if so, then special processing
  1697.  
  1698.            sub cx,dx               ; cx = # bands -1
  1699.            movzx esi,ax            ; si = plane#(x1)
  1700.            and si,plane_bits       ; if left edge is aligned then
  1701.            jz s rf_l_plane_flush   ; no special processing..
  1702.  
  1703. ; draw "left edge" of 1-3 pixels...
  1704.  
  1705.            out_8 sc_data, left_clip_mask[esi] ; set left edge plane mask
  1706.  
  1707.            mov al,colq             ; get fill color
  1708.            mov [edi], al           ; fill in left edge pixels
  1709.  
  1710.            inc edi                 ; point to middle (or right) block
  1711.            dec cx                  ; reset cx instead of jmp s rf_right
  1712.  
  1713. rf_l_plane_flush:
  1714.            inc cx                  ; add in left band to middle block
  1715.  
  1716. ; di = addr of 1st middle pixel (band) to fill
  1717. ; cx = # of bands to fill -1
  1718.  
  1719. rf_right:
  1720.            movzx esi,bx            ; get xpos2
  1721.            and si,plane_bits       ; get plane values
  1722.            cmp si,0003             ; plane = 3?
  1723.            je s rf_r_edge_flush    ; hey, add to middle
  1724.  
  1725. ; draw "right edge" of 1-3 pixels...
  1726.  
  1727.            out_8 sc_data, right_clip_mask[esi] ; right edge plane mask
  1728.  
  1729.            mov esi,edi             ; get addr of left edge
  1730.            add esi,ecx             ; add width-1 (bands)
  1731.            dec esi                 ; to point to top of right edge
  1732.  
  1733.            mov al,colq             ; get fill color
  1734.  
  1735. rf_right_loop:
  1736.            mov [esi], al           ; fill in right edge pixels
  1737.  
  1738.            dec cx                  ; minus 1 for middle bands
  1739.            jz s rf_exit            ; uh.. no middle bands...
  1740.  
  1741. rf_r_edge_flush:
  1742.  
  1743. ; di = addr of upper left block to fill
  1744. ; cx = # of bands to fill in (width)
  1745.  
  1746.            out_8 sc_data, all_planes ; write to all planes
  1747.  
  1748.            mov dx, xactual/4       ; dx = di increment
  1749.            sub dx, cx              ;  = screen_width-# planes filled
  1750.  
  1751.            mov al, colq            ; get fill color
  1752.            mov ah, al              ; colour is in high and low for stosw
  1753.            push ax                 ; make colour 32 bit
  1754.            shl eax,16
  1755.            pop ax
  1756.  
  1757. rf_middle_loop:
  1758.            shr cx,1                ; use doubleword transfer
  1759.            jnc s rf_ord
  1760.            stosb                   ; if cx odd, store byte first
  1761.            jcxz s rf_exit          ; no words after stosb
  1762. rf_ord:
  1763.            shr cx,1
  1764.            jnc rf_dord
  1765.            stosw
  1766.            jcxz s rf_exit          ; no doublewords after stosw
  1767. rf_dord:
  1768.            rep stosd               ; fill in entire line
  1769.  
  1770.            jmp s rf_exit           ; outa here, for this line
  1771.  
  1772. rf_one_band_only:
  1773.            movzx esi,ax               ; get left clip mask, save x1
  1774.            and si,plane_bits          ; mask out row #
  1775.            mov al,left_clip_mask[esi] ; get left edge mask
  1776.            mov si,bx                  ; get right clip mask, save x2
  1777.            and si,plane_bits          ; mask out row #
  1778.            and al,right_clip_mask[esi] ; get right edge mask byte
  1779.  
  1780.            out_8 sc_data, al       ; clip for left & right masks
  1781.  
  1782.            mov al, colq            ; get fill color
  1783.            mov [edi], al           ; fill in pixels
  1784. rf_exit:
  1785.            pop eax ebp edi si      ; pop screen left address
  1786. r_mis:
  1787.            add edi, xactual/4
  1788.            dec rise
  1789.            jg  r_lineloop
  1790.  
  1791. cl_return:
  1792.            ret
  1793.  
  1794. ; bubble sort for sides
  1795.  
  1796. ; sort is not  perfect   since  many  sides  can  use  the  same  point.
  1797. ; if this point is the first point in the list and therefore zeds[] uses
  1798. ; the same point for sort, the routine may mess up when plotting at some
  1799. ; acute angles.  if you ever notice this, you are way  too  picky.   you
  1800. ; could fix this by adjusting the load_sides routine to search  for  the
  1801. ; closest z point.
  1802.  
  1803.            align 16
  1804.  
  1805. minusd equ offset zeds - offset order
  1806.  
  1807. sort_list:
  1808.            movzx esi,showing
  1809.            cmp si,1               ; if only one surface, exit
  1810.            jbe qke
  1811.  
  1812.            shl si,1               ; si = word
  1813.            add esi,o order
  1814.  
  1815.            align 16
  1816. nextcx:
  1817.            sub esi,2              ; point to last word in order[] table
  1818.  
  1819.            mov ebp,esi            ; set order pointer
  1820.            mov bx,w [esi]         ; get order[si]
  1821.  
  1822.            mov edi,esi
  1823.            add edi,minusd
  1824.            mov cx,w [edi]         ; get zeds[si]
  1825.  
  1826.            align 16
  1827. nextdx:
  1828.            sub edi,2
  1829.            sub ebp,2
  1830.  
  1831.            cmp cx,w [edi]         ; zeds is point from side, should be max z
  1832.            jle s donothing
  1833.            xchg cx,w [edi]        ; don't flip entire side, just indexers to it
  1834.            xchg bx,w [ebp]
  1835. donothing:
  1836.            cmp ebp,o order        ; check bp = 0
  1837.            jne s nextdx
  1838.  
  1839.            mov [esi + minusd],cx
  1840.            mov [esi],bx
  1841.  
  1842.            cmp esi,o order + 2
  1843.            jne s nextcx
  1844. qke:
  1845.            ret
  1846.  
  1847. ; routine sets the "final" variables  for   perfect  updvectors  calculations
  1848. ; this fixes the small (and i mean small) discrepancies when the raster count
  1849. ; does not divide evenly into  the   objects   rotational  or  linear  count.
  1850. ; eg lcount =1001, raster count = 10, object should move 1001 units  but gets
  1851. ; moved 100*10 (only moves 1000 units).  this makes  absolutly  sure  that an
  1852. ; object moved to a location in si frames will actually  get  to  that  exact
  1853. ; position! (regardless of machine speed or raster speed or number of objects
  1854. ; on screen or whatever!).
  1855.  
  1856. ; call this routine after setting new anglular or linear velocities. there is
  1857. ; no need to call this routine if you are going to set a position or location
  1858. ; but xxxfinal must be set if you are going to change  the  velocities.   the
  1859. ; variables xxxfinal[] are used by updvectors to set the final position/angle
  1860. ; of an object after the counters lcount and acount have expired. if you know
  1861. ; the final position/angle  of  your  object,  set  these  yourself.  but  if
  1862. ; you only want to move the object and don't care where it will end up,  call
  1863. ; this routine and the final position/angle  will  be   calculated  for  you.
  1864. ; note: xxxfinal variables will only be used if the  raster  count  does  not
  1865. ; divide evenly into the angle/linear count.
  1866.  
  1867. ; routine calculates for object si.
  1868.  
  1869. set_finall:
  1870.            movzx esi,si  ; do this in case user is lazy...
  1871.  
  1872.            movzx ecx,lcount[esi*2] ; final position = speed * time
  1873.  
  1874.            mov eax,xadds[esi*4]    ;        xsfinal = xadds * lcount + position
  1875.            imul ecx              ; you get the idea right?
  1876.            add eax,xs[esi*4]
  1877.            mov xsfinal[esi*4],eax
  1878.  
  1879.            mov eax,yadds[esi*4]
  1880.            imul ecx
  1881.            add eax,ys[esi*4]
  1882.            mov ysfinal[esi*4],eax
  1883.  
  1884.            mov eax,zadds[esi*4]
  1885.            imul ecx
  1886.            add eax,zs[esi*4]
  1887.            mov zsfinal[esi*4],eax
  1888.  
  1889.            ret
  1890.  
  1891. set_finala:
  1892.            movzx esi,si  ; do this in case user is lazy...
  1893.  
  1894.            mov cx,acount[esi*2]  ; final angle = angular velocity * time
  1895.  
  1896.            mov ax,vxadds[esi*2]    ;    vxsfinal = vxadds * acount + angle
  1897.            imul cx
  1898.            add ax,vxs[esi*2]
  1899.            mov vxsfinal[esi*2],ax
  1900.  
  1901.            mov ax,vyadds[esi*2]
  1902.            imul cx
  1903.            add ax,vys[esi*2]
  1904.            mov vysfinal[esi*2],ax
  1905.  
  1906.            mov ax,vzadds[esi*2]
  1907.            imul cx
  1908.            add ax,vzs[esi*2]
  1909.            mov vzsfinal[esi*2],ax
  1910.  
  1911.            ret
  1912.  
  1913.            align 16
  1914.  
  1915. ; point object si at object di
  1916.  
  1917. point_it:
  1918.            push esi edi
  1919.            xchg si,di        ; xchange so user doesn't get confused
  1920.            push di
  1921.            call calc_angles
  1922.            pop di
  1923.            movzx edi,di
  1924.            mov vxs[edi*2],ax
  1925.            mov vys[edi*2],bx
  1926.            pop edi esi
  1927.  
  1928.            ret
  1929.  
  1930.            align 16
  1931.  
  1932. ; point object si in direction it is moving
  1933.  
  1934. point_dir:
  1935.            movzx esi,si
  1936.  
  1937.            mov ebx,xadds[esi*4]
  1938.            mov ecx,yadds[esi*4]
  1939.            mov ebp,zadds[esi*4]
  1940.  
  1941.            shl ebx,4        ; * whatever to get some decimal accuracy
  1942.            shl ecx,4
  1943.            shl ebp,4
  1944.  
  1945.            align 16
  1946.  
  1947. ; point object si at location ebx,ecx,ebp.
  1948.  
  1949. point_to:
  1950.            mov di,si        ; xchange so user doesn't get confused
  1951.            movzx edi,di
  1952.            push edi
  1953.  
  1954.            sub ebx,xs[edi*4]        ; get displacement of esi to edi
  1955.            sub ecx,ys[edi*4]
  1956.            sub ebp,zs[edi*4]
  1957.  
  1958.            call calc_middle
  1959.  
  1960.            pop esi
  1961.            mov vxs[esi*2],ax
  1962.            mov vys[esi*2],bx
  1963.  
  1964.            ret
  1965.  
  1966.            align 16
  1967.  
  1968. ; set speed of object si to ebp*angle, then set lcount to di
  1969. ; (move object in direction it is pointing)
  1970.  
  1971. ;
  1972. ; xadds=  - cx * sy  * ebp
  1973. ;
  1974. ; yadds=    - sx     * ebp
  1975. ;
  1976. ; zadds=    cx * cy  * ebp
  1977.  
  1978. set_speed:
  1979.            movzx esi,si
  1980.            mov lcount[esi*2],di
  1981.  
  1982.            mov ax,vxs[esi*2]
  1983.            neg ax
  1984.            push ax
  1985.            call cosign
  1986.            mov ecx,eax            ; cx = cos x
  1987.            pop ax
  1988.            call sign
  1989.  
  1990.            neg eax
  1991.            imul ebp               ; set y speed
  1992.            shrd eax,edx,14
  1993.            mov yadds[esi*4],eax
  1994.  
  1995.            mov ax,vys[esi*2]
  1996.            neg ax
  1997.            push ax
  1998.            call cosign
  1999.            mov edx,eax            ; dx = cos y
  2000.            pop ax
  2001.            call sign
  2002.  
  2003.            mov ebx,edx            ; save because imul trashes dx
  2004.  
  2005.            imul ecx               ; ax = sy * cx
  2006.            shrd eax,edx,14        ; shr eax,14 compensates for cos decimals
  2007.            imul ebp
  2008.            shrd eax,edx,14
  2009.            neg eax
  2010.            mov xadds[esi*4],eax
  2011.  
  2012.            mov eax,ebx
  2013.            imul ecx
  2014.            shrd eax,edx,14
  2015.            imul ebp
  2016.            shrd eax,edx,14
  2017.            mov zadds[esi*4],eax
  2018.  
  2019.            ret
  2020.  
  2021. ; point object si at location ebx,ecx,ebp, in di frames (di = time)
  2022.  
  2023. ; this could also be used for the camera, but if you are  going  to
  2024. ; point the camera at an object, call newfollow instead.  newfollow
  2025. ; allows for when the object is moving - newfollow will  track  the
  2026. ; object as it moves and even if it accelerates!
  2027.  
  2028. point_time:
  2029.            push di si di si ebp ecx ebx
  2030.            call where_si     ; find out where object will be in di frames
  2031.  
  2032.            pop eax
  2033.            sub ebx,eax       ; get displacement of where it will be to where
  2034.            neg ebx           ; it should point
  2035.  
  2036.            pop eax
  2037.            sub ecx,eax
  2038.            neg ecx
  2039.  
  2040.            pop eax
  2041.            sub ebp,eax
  2042.            neg ebp
  2043.  
  2044.            pop di si         ; notice reverse order for calc_middle
  2045.  
  2046.            call calc_middle
  2047.            movzx ecx,bx
  2048.            movzx ebx,ax
  2049.  
  2050.            test bx,8000h     ; test to invert for other direction
  2051.            jne no_inv1
  2052.            xor ecx,0ffff0000h ; xor goes the other way
  2053. no_inv1:
  2054.            test cx,8000h
  2055.            jne no_inv2
  2056.            xor ecx,0ffff0000h
  2057. no_inv2:
  2058.            pop si            ; pop object number
  2059.            pop di            ; pop time
  2060.            movzx esi,si
  2061.  
  2062.            mov ax,vzadds[esi*2] ; figure out z (calc_middle wont)
  2063.            imul di
  2064.            add ax,vzs[esi*2]
  2065.  
  2066.            movzx ebp,ax
  2067.            test bp,8000h
  2068.            jne no_inv3
  2069.            neg ebp
  2070. no_inv3:
  2071. ;          add ebx,00010000h ; do this if you want more than one rotation
  2072. ;          add ecx,00020000h ; along a selected axis.
  2073. ;          add ebp,00030000h ; maybe put a ret here then call twist_si yourself
  2074.  
  2075.            jmp twist_si      ; twist object to this location in di frames!
  2076.  
  2077. nullpalette:
  2078.            i=0
  2079.            rept 256
  2080.            db i
  2081.            i=i+1
  2082.            endm
  2083.  
  2084. set_xref_palette:            ; set cross referencing palette for object si
  2085.            movzx esi,si
  2086.            mov palxref[esi*4],ebx
  2087.            ret
  2088.  
  2089.